package com.walle.ak47.commons.utils;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;

public class ClassUtils
{
	public static Class<?> getRealClass( Object _obj )
	{
		if( _obj == null )
			return null ;
		else
		{
			String temp = _obj.getClass().getName() ;
			int i= temp.indexOf( "[L" ) ;
			if( i >= 0 )
				temp = temp.substring( 2 , temp.indexOf( ';' ) ) ;

			return loadClass( temp ) ;
		}
	}

	public static String getRealClassName( Object _obj )
	{
		if( _obj == null )
			return null ;
		else
		{
			String temp = _obj.getClass().getName() ;
			int i= temp.indexOf( "[L" ) ;
			if( i >= 0 )
				temp = temp.substring( 2 , temp.indexOf( ';' ) ) ;

			return temp ;
		}
	}

	public static ClassLoader newClassLoader( String[] _urls )
	{
		return newClassLoader( _urls , ClassUtils.class.getClassLoader() ) ;
	}

	public static ClassLoader newClassLoader( String[] _urls , ClassLoader _parent )
	{
		if( _urls == null || _urls.length <= 0 )
			return null ;
		
		try
		{
			URL[] urls = new URL[ _urls.length ] ;
			for( int i=0 ; i<_urls.length ; i++ )
			{
				if( !_urls[i].toLowerCase().startsWith( "http://" ) )
					_urls[i] = "file://" + _urls[i] ;
				
				if( _urls[i].endsWith( ".jar" ) || _urls[i].endsWith( ".class" ) )
					urls[i] = new URL( _urls[i] ) ;
				else if( _urls[i].endsWith( RuntimeUtils.FILE_SEPARATOR ) )
					urls[i] = new URL( _urls[i] ) ;
				else
					urls[i] = new URL( _urls[i] + RuntimeUtils.FILE_SEPARATOR ) ;
			}
			return newClassLoader( urls , _parent ) ;
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static ClassLoader newClassLoader(String _path)
	{
		try
		{
			URL url = new URL(_path);
			return newClassLoader(new URL[] { url });
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static ClassLoader newClassLoader(String _path, ClassLoader _parent)
	{
		try
		{
			URL url = new URL(_path);
			return newClassLoader(new URL[] { url }, _parent);
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static ClassLoader newClassLoader(URL[] _urls)
	{
		return new URLClassLoader(_urls);
	}

	public static ClassLoader newClassLoader(URL[] _urls, ClassLoader _parent)
	{
		return new URLClassLoader(_urls, _parent);
	}

	public static URL getResourceAsURL(String _resourceName)
	{
		return ClassUtils.class.getClassLoader().getResource(
				_resourceName);
	}
	
	public static InputStream getResourceAsStream( String _resourceName )
	{
		return ClassUtils.class.getClassLoader().getResourceAsStream( _resourceName ) ;
	}

	public static Enumeration<URL> getResources(String _resourceName)
	{
		try
		{
			return ClassUtils.class.getClassLoader().getResources(
					_resourceName);
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static URL getResourceAsURL(String _resourceName, ClassLoader _classLoader)
	{
		return _classLoader.getResource(_resourceName);
	}

	public static InputStream getResourceAsStream(String _resourceName, ClassLoader _classLoader)
	{
		return _classLoader.getResourceAsStream(_resourceName);
	}

	public static Enumeration<URL> getResources(String _resourceName,
			ClassLoader _classLoader)
	{
		try
		{
			return _classLoader.getResources(_resourceName);
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static Class<?> loadClass( String _clzName )
	{
		return loadClass( _clzName , ClassUtils.class.getClassLoader() ) ;
	}
	
	public static Class<?> loadClass( String _clzName , ClassLoader _loader )
	{
		try
		{
			return _loader.loadClass( _clzName ) ;
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static Object newInstance( Class<?> _clz )
	{
		return newInstance( _clz , null , null ) ;
	}

	public static Object newInstance(Class<?> _clz, Class<?>[] _paramClassess,
			Object[] _paramValues)
	{
		try
		{
			if (_paramClassess == null || _paramValues == null)
				return _clz.newInstance();
			else
			{
				Constructor<?> constructor = _clz.getConstructor(_paramClassess);
				return constructor.newInstance(_paramValues);
			}
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static String getPackageName(Class<?> _clz)
	{
		Package clazzPackage = _clz.getPackage();
		String packageName;
		if (clazzPackage != null)
			packageName = clazzPackage.getName();
		else
		{
			String clazzName = _clz.getName();
			packageName = clazzName.substring(0, clazzName.lastIndexOf('.'));
		}
		return packageName;

	}
	
	public static Method getMethod( Class<?> _clz , String _method , Class<?>[] _types )
	{
		try
		{
			if( _types == null )
				return _clz.getMethod( _method , new Class[]{} ) ;
			else
				return _clz.getMethod( _method , _types ) ;
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static Method getMethod( Class<?> _clz , String _method , Object[] _arguments )
	{
		try
		{
			if( _arguments == null )
				return _clz.getMethod( _method , new Class[]{} ) ;
			else
			{
				Class<?>[] types = new Class[_arguments.length] ;
				for( int i=0 ; i<_arguments.length ; i++ )
					types[i] = (_arguments[i]==null?Object.class:_arguments[i].getClass()) ;
				
				return _clz.getMethod( _method , types ) ;
			}
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static Method getSingletonMethod( Class<?> _clz , String _method )
	{
		Method[] methods = _clz.getMethods() ;
		for( int i=0 ; methods!=null && i<methods.length ; i++  )
		{
			if( methods[i].getName().equals( _method ) )
				return methods[i] ;
		}
		
		return null ;
	}
}